/**
 * 发送朋友圈
 *
 * 业务实体关系：
 * - SendMomentConfig          发朋友圈配置：用哪些企业微信、发送什么内容
 *    - SendMomentTask         发朋友圈配置启用后，会为其中每个企业微信开启一个 task，即发送任务
 */
import { Service } from '@gnlab/utils'
import flatMap from 'lodash/flatMap'
import { makeHTTPSAvatar } from '@/lib/https'
import { toISOString } from '@/lib/utils'
import type { Services } from '@/services'
import { API } from '@/services/common/api'
import { makeContactId } from '@/services/contacts'
import { friendlyQywxName } from '@/services/qywxs'

/**
 * =================================
 * 朋友圈内容
 * =================================
 *
 * 后端是把“纯文本”当作单独的类型，即：
 * - 纯文本
 * - 图片/视频/链接 + 可选文本
 *
 * 而前端是把文本和多媒体内容抽离
 * - textOnly=true + text           对应后端的“纯文本”类型
 * - textOnly=false + text + media  对应其他类型
 */
export interface MomentContent {
  textOnly: boolean
  text: string

  mediaType: MediaType
  picturePaths: string[] // 图片内容的图片列表，最多 9 个
  videoPath: string // 视频内容的视频网址
  linkTitle: string // 链接内容的标题
  linkUrl: string // 链接内容的网址
  linkPicturePath: string // 链接内容的图片网址
}

export enum MediaType {
  Picture = 1, // 图片
  Video = 2, // 视频
  LinkCard = 3, // 链接卡片
}

export function getEmptyContent(): MomentContent {
  return {
    textOnly: false,
    text: '',
    mediaType: MediaType.Picture,
    picturePaths: [],
    videoPath: '',
    linkTitle: '',
    linkUrl: '',
    linkPicturePath: '',
  }
}

enum RawMediaType {
  Text = 0, // 纯文本
  Picture = 1, // 图片
  Video = 2, // 视频
  LinkCard = 3, // 链接卡片
}

interface RawMomentContent {
  Type: RawMediaType
  Text: string
  FilePathList: string[] // 图片路径列表（链接会使用此列表第一个图片作为链接图片）
  VideoPath: string // 视频路径
  Title: string // 链接标题
  Url: string // 链接网址
}

function formatRawMomentContent(raw: RawMomentContent): MomentContent {
  return {
    textOnly: raw.Type === RawMediaType.Text,
    text: raw.Text,

    mediaType:
      raw.Type === RawMediaType.Text ? MediaType.Picture : (raw.Type as unknown as MediaType),
    picturePaths: raw.FilePathList,
    videoPath: raw.VideoPath,
    linkTitle: raw.Title,
    linkUrl: raw.Url,
    linkPicturePath: raw.Type === RawMediaType.LinkCard ? raw.FilePathList[0] ?? '' : '',
  }
}

function makeRawMomentContent(content: MomentContent): RawMomentContent {
  return {
    Type: content.textOnly ? RawMediaType.Text : (content.mediaType as unknown as RawMediaType),
    Text: content.text,
    FilePathList:
      content.mediaType === MediaType.LinkCard
        ? content.linkPicturePath
          ? [content.linkPicturePath]
          : []
        : content.picturePaths,
    VideoPath: content.videoPath,
    Title: content.linkTitle,
    Url: content.linkUrl,
  }
}

/**
 * =================================
 * 可见客户
 * =================================
 */
export type ConfigAboutContacts = Pick<BaseSendMomentConfig, 'wxids' | 'contacts'>

export interface MomentContact {
  id: string
  ownerWxid: string
  contactUserId: string
  tagIds: string[] // 通过哪些标签选中了此客户；其中空字符串是特殊值，代表通过手动选择的方式选择了此客户
}

interface RawMomentQywxContacts {
  WxId: string
  UserList: RawMomentContact[]
}

interface RawMomentContact {
  UserId: string
  LabelId: string[]
}

function formatRawMomentContacts(
  ownerWxid: string,
  rawContacts: RawMomentContact[],
): MomentContact[] {
  return rawContacts.map(rawItem => ({
    id: makeContactId(ownerWxid, rawItem.UserId),
    ownerWxid,
    contactUserId: rawItem.UserId,
    tagIds: rawItem.LabelId,
  }))
}

function formatRawMomentQywxContactsList(raw: RawMomentQywxContacts[]): ConfigAboutContacts {
  const contacts = flatMap(raw, rawQywx => formatRawMomentContacts(rawQywx.WxId, rawQywx.UserList))
  return {
    wxids: raw.map(rawQywx => rawQywx.WxId),
    contacts: contacts.length ? contacts : null,
  }
}

function makeRawMomentQywxContactList(config: ConfigAboutContacts): RawMomentQywxContacts[] {
  const map = new Map<string, RawMomentQywxContacts>()
  if (config.contacts) {
    // 没有指定联系人的企业微信会被自动过滤掉
    for (const contact of config.contacts) {
      const wxid = contact.ownerWxid
      if (!map.has(wxid)) map.set(wxid, { WxId: wxid, UserList: [] })
      map.get(contact.ownerWxid)?.UserList.push({
        UserId: contact.contactUserId,
        LabelId: contact.tagIds,
      })
    }
  } else {
    for (const wxid of config.wxids) map.set(wxid, { WxId: wxid, UserList: [] })
  }
  return [...map.values()]
}

/**
 * =================================
 * 发朋友圈配置
 * =================================
 */

/**
 * 配置发送状态
 */
export enum SendMomentConfigStatus {
  Idle = 0, // 待发送（立即发送的任务刚保存时也可能处于此状态）
  Cancelled = 3, // 已取消
  Sending = 1, // 发送中
  Sended = 2, // 发送完成
}

/**
 * 发朋友圈配置
 * 注意：此对象不包含 `wxids 企业微信列表` 和 `scope 可见范围` 数据
 */
export interface BaseSendMomentConfig {
  status: SendMomentConfigStatus
  name: string // 名称
  wxids: string[]
  content: MomentContent // 朋友圈内容
  contacts: MomentContact[] | null // 可见客户。为 null 代表所有客户可见
  sendTime: number | null // 定时发布时间；为 null 代表立即发布
}

export interface SendMomentConfig extends BaseSendMomentConfig {
  id: number
}

interface RawBaseSendMomentConfig extends RawMomentContent {
  Name: string
  Status: SendMomentConfigStatus
  WxList: RawMomentQywxContacts[]
  SendTime: string | null
}

interface RawSendMomentConfig extends RawBaseSendMomentConfig {
  Id: number
}

function formatRawSendMomentConfig(raw: RawSendMomentConfig): SendMomentConfig {
  return {
    id: raw.Id,
    name: raw.Name,
    status: raw.Status,
    sendTime: raw.SendTime !== null ? new Date(raw.SendTime).getTime() / 1000 : null,
    content: formatRawMomentContent(raw),
    ...formatRawMomentQywxContactsList(raw.WxList),
  }
}

/**
 * 把前端的 config 数据转换成后端需要的
 */
export function makeRawSendMomentConfig(config: BaseSendMomentConfig): RawBaseSendMomentConfig {
  return {
    Name: config.name,
    Status: config.status,
    WxList: makeRawMomentQywxContactList(config),
    SendTime: config.sendTime !== null ? toISOString(config.sendTime * 1000) : null,
    ...makeRawMomentContent(config.content),
  }
}

/**
 * 取得一个空的发送配置
 */
export function getEmptySendMomentConfig(): BaseSendMomentConfig {
  return {
    name: '',
    status: SendMomentConfigStatus.Idle,
    wxids: [],
    content: getEmptyContent(),
    contacts: null,
    sendTime: null,
  }
}

/**
 * =================================
 * 朋友圈配置涉及的企业微信
 * =================================
 */
export interface SendMomentConfigQywx {
  wxid: string
  avatar: string
  username: string
  nickname: string
  corpname: string
  friendlyName: string
  friendlyFullName: string
  accountName: string
  accountRemark: string
  configId?: number | null // number: 此企业微信被加入了哪个配置，为 null 代表还没有被加入配置
}

interface RawSendMomentConfigQywx {
  WxId: string
  Avatar: string
  UserName: string
  NickName: string
  CorpName: string
  UserAccountName: string
  UserAccountRemarkName: string | null
  ConfigId: number
}

function formatRawSendMomentConfigQywx(raw: RawSendMomentConfigQywx): SendMomentConfigQywx {
  const base = {
    wxid: raw.WxId,
    username: raw.UserName,
    nickname: raw.NickName,
    corpname: raw.CorpName,
    avatar: makeHTTPSAvatar(raw.Avatar),
    accountName: raw.UserAccountName,
    accountRemark: raw.UserAccountRemarkName ?? '',
    configId: raw.ConfigId === 0 ? null : raw.ConfigId,
  }
  return {
    ...base,
    friendlyName: friendlyQywxName(base, false),
    friendlyFullName: friendlyQywxName(base),
  }
}

/**
 * =================================
 * 朋友圈配置任务详情
 * =================================
 */
export enum SendMomentTaskStatus {
  Idle = 0, // 待发送
  Sended = 1, // 已发送
  Failed = 2, // 发送失败
}

export interface SendMomentTask {
  id: number // 任务 id
  wxid: string // 企业微信 id
  status: SendMomentTaskStatus // 任务状态
  message: string // 若任务失败，此为失败说明
  contacts: MomentContact[] | null // 可见范围，为 nul 代表全部客户可见
}

interface RawSendMomentTask {
  Id: number
  WxId: string
  Status: SendMomentTaskStatus
  FailedReason: string
  UserList: RawMomentContact[]
}

function formatSendMomentTask(raw: RawSendMomentTask): SendMomentTask {
  return {
    id: raw.Id,
    wxid: raw.WxId,
    status: raw.Status,
    message: raw.FailedReason,
    contacts: raw.UserList.length ? formatRawMomentContacts(raw.WxId, raw.UserList) : null,
  }
}

// =====================================================================

export class SendMoment extends Service<Services> {
  /**
   * 获取用于发朋友圈配置的企业微信列表
   *
   * 若指定 configId，则返回所有在线企业微信，以及处于这个 config 中但是不在线的企业微信
   * 若不指定 configId，则仅返回所有在线企业微信
   */
  async getQywxListForConfig(configId?: number) {
    return API('/FriendMoments/GetFriendMomentsWxUserList', {
      data: { ConfigId: configId },
      formatter(raw: RawSendMomentConfigQywx[]) {
        return raw.map(formatRawSendMomentConfigQywx)
      },
    })
  }

  async loadConfigs() {
    return API('/FriendMoments/GetFriendMomentsConfigs', {
      formatter(list: RawSendMomentConfig[]) {
        return list.map(formatRawSendMomentConfig)
      },
    })
  }

  async addOrUpdateConfig(data: BaseSendMomentConfig & { id?: number }) {
    return API('/FriendMoments/SaveFriendMomentsConfig', {
      data: {
        Id: data.id,
        ...makeRawSendMomentConfig(data),
      },
      formatter() {},
    })
  }

  async loadTasks(configId: number) {
    return API('/FriendMoments/GetFriendMomentsTasks', {
      data: {
        Id: configId,
      },
      formatter(raw: RawSendMomentTask[]) {
        return raw.map(formatSendMomentTask)
      },
    })
  }
}
